package com.zycfc.zsf.boot.util.collection;

import com.google.common.collect.*;
import java.util.concurrent.*;
import java.util.*;

public abstract class ListUtils
{
    public static boolean isEmpty(final List<?> list) {
        return list == null || list.isEmpty();
    }
    
    public static boolean isNotEmpty(final List<?> list) {
        return list != null && !list.isEmpty();
    }
    
    public static <T> T getFirst(final List<T> list) {
        if (isEmpty(list)) {
            return null;
        }
        return list.get(0);
    }
    
    public static <T> T getLast(final List<T> list) {
        if (isEmpty(list)) {
            return null;
        }
        return list.get(list.size() - 1);
    }
    
    public static <T> ArrayList<T> newArrayList() {
        return new ArrayList<T>();
    }
    
    @SafeVarargs
    public static <T> ArrayList<T> newArrayList(final T... elements) {
        return (ArrayList<T>)Lists.newArrayList((Object[])elements);
    }
    
    public static <T> ArrayList<T> newArrayList(final Iterable<T> elements) {
        return (ArrayList<T>)Lists.newArrayList((Iterable)elements);
    }
    
    public static <T> ArrayList<T> newArrayListWithCapacity(final int initSize) {
        return new ArrayList<T>(initSize);
    }
    
    public static <T> LinkedList<T> newLinkedList() {
        return new LinkedList<T>();
    }
    
    public static <T> CopyOnWriteArrayList<T> newCopyOnWriteArrayList() {
        return new CopyOnWriteArrayList<T>();
    }
    
    @SafeVarargs
    public static <T> CopyOnWriteArrayList<T> newCopyOnWriteArrayList(final T... elements) {
        return new CopyOnWriteArrayList<T>(elements);
    }
    
    public static final <T> List<T> emptyList() {
        return Collections.emptyList();
    }
    
    public static <T> List<T> emptyListIfNull(final List<T> list) {
        return (list == null) ? Collections.emptyList() : list;
    }
    
    public static <T> List<T> singletonList(final T o) {
        return Collections.singletonList(o);
    }
    
    public static <T> List<T> unmodifiableList(final List<? extends T> list) {
        return Collections.unmodifiableList(list);
    }
    
    public static <T> List<T> synchronizedList(final List<T> list) {
        return Collections.synchronizedList(list);
    }
    
    public static <T extends Comparable<? super T>> void sort(final List<T> list) {
        Collections.sort(list);
    }
    
    public static <T extends Comparable<? super T>> void sortReverse(final List<T> list) {
        Collections.sort(list, Collections.reverseOrder());
    }
    
    public static <T> void sort(final List<T> list, final Comparator<? super T> c) {
        Collections.sort(list, c);
    }
    
    public static <T> void sortReverse(final List<T> list, final Comparator<? super T> c) {
        Collections.sort(list, (Comparator<? super T>)Collections.reverseOrder((Comparator<? super T>)c));
    }
    
    public static <T> int binarySearch(final List<? extends Comparable<? super T>> sortedList, final T key) {
        return Collections.binarySearch(sortedList, key);
    }
    
    public static <T> int binarySearch(final List<? extends T> sortedList, final T key, final Comparator<? super T> c) {
        return Collections.binarySearch(sortedList, key, c);
    }
    
    public static void shuffle(final List<?> list) {
        Collections.shuffle(list);
    }
    
    public static <T> List<T> reverse(final List<T> list) {
        return (List<T>)Lists.reverse((List)list);
    }
    
    public static void shuffle(final List<?> list, final Random rnd) {
        Collections.shuffle(list, rnd);
    }
    
    public static <E> List<E> union(final List<? extends E> list1, final List<? extends E> list2) {
        final ArrayList<E> result = new ArrayList<E>(list1.size() + list2.size());
        result.addAll(list1);
        result.addAll(list2);
        return result;
    }
    
    public static <T> List<T> intersection(final List<? extends T> list1, final List<? extends T> list2) {
        final List<T> result = new ArrayList<T>();
        List<? extends T> smaller = list1;
        List<? extends T> larger = list2;
        if (list1.size() > list2.size()) {
            smaller = list2;
            larger = list1;
        }
        final List<T> newSmaller = new ArrayList<T>(smaller);
        for (final T e : larger) {
            if (newSmaller.contains(e)) {
                result.add(e);
                newSmaller.remove(e);
            }
        }
        return result;
    }
    
    public static <T> List<T> difference(final List<? extends T> list1, final List<? extends T> list2) {
        final ArrayList<T> result = new ArrayList<T>(list1);
        final Iterator<? extends T> iterator = list2.iterator();
        while (iterator.hasNext()) {
            result.remove(iterator.next());
        }
        return result;
    }
    
    public static <T> List<T> disjoint(final List<? extends T> list1, final List<? extends T> list2) {
        final List<T> intersection = (List<T>)intersection((List<?>)list1, (List<?>)list2);
        final List<T> towIntersection = union((List<? extends T>)intersection, (List<? extends T>)intersection);
        return (List<T>)difference(union((List<?>)list1, (List<?>)list2), (List<?>)towIntersection);
    }
}
